package com.soxing.webrain.brush.service.work;


import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.jmatio.io.MatFileReader;
import com.jmatio.types.*;
import com.soxing.webrain.brush.dao.entity.Algorithm;
import com.soxing.webrain.brush.dao.entity.Paradigm;
import com.soxing.webrain.brush.dao.entity.StatResult;
import com.soxing.webrain.brush.dao.entity.Task;
import com.soxing.webrain.brush.dao.service.impl.AlgorithmServiceImpl;
import com.soxing.webrain.brush.dao.service.impl.ParadigmServiceImpl;
import com.soxing.webrain.brush.dao.service.impl.StatResultServiceImpl;
import com.soxing.webrain.brush.dao.service.impl.TaskServiceImpl;
import com.soxing.webrain.brush.service.docker.MyDockerClient;
import com.soxing.webrain.brush.service.FeedBackServiceImpl;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

@Configuration
@EnableScheduling
public class TaskDispatch {
    private static final Logger logger = LoggerFactory.getLogger(TaskDispatch.class);

    @Resource
    TaskServiceImpl taskService;

    @Resource
    AlgorithmServiceImpl algorithmService;

    @Resource
    ParadigmServiceImpl paradigmService;

    @Resource
    StatResultServiceImpl statResultService;

    @Resource
    MyDockerClient myDockerClient;

    @Resource
    FeedBackServiceImpl feedBackService;


    @Scheduled(cron = "0 0/1 * * * ?")
    public void execute() throws Exception {
        logger.info("定时任务");

        List<Task> pList = dispatch();
        if (CollectionUtils.isEmpty(pList)) {
            return;
        }

        for (Task p : pList) {
            // 执行中
            p.setStatus(6);
            taskService.updateById(p);

            logger.info("开始启动容器");
            Paradigm paradigm = paradigmService.getById(p.getParadigmId());
            Algorithm algorithm = algorithmService.getById(paradigm.getReportAlgorithmId());
            String image = algorithm.getImage();
            String imageName = algorithm.getName();
            String containerId = myDockerClient.createReportJob(p, imageName, image);

            logger.info("启动好容器了");
            if (containerId == null) {
                // 执行失败
                p.setStatus(5);
                taskService.updateById(p);
                return;
            }

            try {
                StatResult statResult = new StatResult();
                String code = "ONE_VALUE_" + p.getTesteeId() + "_" + p.getId() + "_NETWORK_SINGLE";
                statResult.setCode(code);
                statResult.setTesteeId(p.getTesteeId());
                statResult.setTaskId(p.getId());
                statResult.setType(0);

                logger.info("读取文件");
                File target = feedBackService.getLastModifiedFile(new File(p.getMountPath() + "results/" + p.getId() + "/result_average"), ".mat");
                if (target == null) {
                    p.setStatus(5);
                    taskService.updateById(p);
                    return;
                }
                MatFileReader reader = null;
                try {
                    reader = new MatFileReader(target);
                } catch (IOException e) {
                    e.printStackTrace();
                    p.setStatus(5);
                    taskService.updateById(p);
                    return;
                }

                MLStructure r1 = (MLStructure) reader.getContent().get("results");

                logger.info("获取结果");
                // 获取averageFeedbackValue变量
                double oneValue = ((MLDouble) r1.getField("averageFeedbackValue")).getArray()[0][0];
                BigDecimal bd = new BigDecimal(oneValue);
                bd = bd.setScale(2, RoundingMode.HALF_UP); // 设置小数点后两位，四舍五入
                double roundedValue = bd.doubleValue(); // 转换回double类型
                statResult.setStatValue(roundedValue * 100);

                // 获取feedbackValues变量
                double[] values = ((MLDouble)r1.getField("feedbackValues")).getArray()[0];
                for (int i = 0; i < values.length; i++) {
                    values[i] *= 100;
                }

                // 获取feedbackFiles变量
                MLCell filesArray = ((MLCell)r1.getField("feedbackFiles"));
                String[] files = new String[filesArray.getN()];
                for (int i = 0; i < filesArray.getN(); i++) {
                    files[i] = ((MLChar)filesArray.get(0,i)).getString(0);
                }

                JSONObject jsonObject = new JSONObject();
                jsonObject.put("averageFeedbackValue", roundedValue * 100);
                jsonObject.put("feedbackValues", values);
                jsonObject.put("feedbackFiles", files);
                String jsonString = jsonObject.toString();
                statResult.setStatJson(jsonString);

                statResultService.save(statResult);
                logger.info("成功!!");
                p.setStatus(4);
                taskService.updateById(p);
            } catch (Exception e) {
                e.printStackTrace();
                p.setStatus(5);
                taskService.updateById(p);
            }

        }
    }

    public List<Task> dispatch() {
        // String maxTasksStr = parameterService.getValue(SystemParameterEnum.maxTasks.getKey());
        // if (maxTasksStr == null) {
        //     maxTasksStr = "20";
        // }
        // int maxTasks = Integer.valueOf(maxTasksStr);
        Integer maxTasks = 20;

        Map<String, Object> params = new HashMap<>();
        // 任务状态 -1:信息不完整 0:未执行 5:等待执行 1:执行中 2:执行成功 3:执行失败 4:终止执行
        // 任务状态 -1:信息不完整  0:未开始  1:训练中 2:终止训练 3:等待评估 4:评估中 5:评估成功 6:执行失败
        params.put("status", 3);
        // 等待执行的任务
        List<Task> waitingProjectList = taskService.listByMap(params);
        if (CollectionUtils.isEmpty(waitingProjectList)) {
            logger.info("没有需要执行的任务");
            return null;
        }
        logger.info("待执行任务数:" + waitingProjectList.size());

        params.clear();
        params.put("status", 1);
        // 正在执行的任务数
        List<Task> runningProjectList = taskService.listByMap(params);
        // 正在执行的任务数
        int runningCount = runningProjectList == null ? 0 : runningProjectList.size();
        logger.info("当前正在执行的任务数为:" + runningCount);

        // 还能执行任务数
        int leftCount = maxTasks - runningCount;
        logger.info("系统剩余任务执行能力:" + leftCount);
        if (leftCount <= 0) {
            return null;
        }
        leftCount = Math.min(waitingProjectList.size(), leftCount);
        logger.info("本次执行任务数:" + leftCount);
        return waitingProjectList.subList(0, leftCount);
    }

}
